#include <stdio.h>

#include "console.h"
#include "config.h"
#include "tex/TeX.h"
#include "syscalls.h"
#include "memory.h"

#define POPUP_PRETTY 1
#define POPUP_PRETTY_STR "Pretty print"

extern void run(char *s);

static struct line Line[LINE_MAX];
static char FMenu_entries_name[6*FMENU_TITLE_LENGHT+1] = {'\0'};
static struct location Cursor;
static unsigned char *Edit_Line;
static int Start_Line, Last_Line;
static int Case;

#define Current_Line (Start_Line + Cursor.y)
#define Current_Col (Line[Cursor.y + Start_Line].start_col + Cursor.x)

/*
	ÒÔÏÂº¯Êý½«ÓÃÓÚÉ¾³ý×Ö·û´®Ö¸¶¨Î»ÖÃÖ®Ç°¹²n¸ö×Ö·û¡£ÆäÖÐ£¬1¸ö¿í×Ö·û£¨Õ¼2×Ö½Ú£©½«Ëã×÷1¸ö×Ö·û¡£

	ÀýÈç£¬ÎÒÃÇÓÐÈçÏÂ×Ö·û´®str£º

	Î»ÖÃ | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
	×Ö·û |'a'|'b'|'c'|'d'|'e'|'f'| 0 |

	Ôòµ÷ÓÃConsole_DelStr(str, 3, 2)ºó£¬Î»ÖÃ1¡¢2µÄ×Ö·û½«±»É¾³ý£¬ÆäºóµÄ×Ö·û½«±»ÌáÇ°¡£
	½á¹ûÈçÏÂ£º

	Î»ÖÃ | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
	×Ö·û |'a'|'d'|'e'|'f'| 0 |'f'| 0 |

	£¨×¢Òâ£º¶àÓàµÄÎ»ÖÃ²¢²»»á±»Ìî³äÎª'\0'£¬µ«ÊÇÔ­×Ö·û´®Ä©Î²µÄ'\0'½«±»¿½±´¡££©

	The following functions will be used to specify the location before deleting a string of n characters altogether. Among them, a wide character (2 bytes) will be counted as a character.
	
	For example, we have the following string str:
	
	Location  |  0  |  1  |  2  |  3  |  4  |  5  | 6 |
	Character | 'a' | 'b' | 'c' | 'd' | 'e' | 'f' | 0 |

	After the call Console_DelStr (str, 3, 2), position 1 and 2 characters will be deleted, then the characters will be in advance.
	
	Results are as follows:

	Location  |  0  |  1  |  2  |  3  | 4 |  5  | 6 |
	Character | 'a' | 'd' | 'e' | 'f' | 0 | 'f' | 0 |

	(Note: the extra positions will not be filled with '\ 0', but '\ 0' will be a copy of the original end of the string.)

*/

int Console_DelStr(unsigned char *str, int end_pos, int n)
{
	int str_len, actual_end_pos, start_pos, actual_start_pos, del_len, i;

	str_len = strlen((const char *)str);
	if ((start_pos = end_pos - n) < 0) return CONSOLE_ARG_ERR;

	if ((actual_end_pos = Console_GetActualPos(str, end_pos)) == CONSOLE_ARG_ERR) return CONSOLE_ARG_ERR;
	if ((actual_start_pos = Console_GetActualPos(str, start_pos)) == CONSOLE_ARG_ERR) return CONSOLE_ARG_ERR;

	del_len = actual_end_pos - actual_start_pos;

	for (i = actual_start_pos; i < str_len; i++)
	{
		str[i] = str[i + del_len];
	}

	return CONSOLE_SUCCEEDED;
}

/*
	ÒÔÏÂº¯ÊýÓÃÓÚÔÚÖ¸¶¨Î»ÖÃ²åÈëÖ¸¶¨µÄ×Ö·û´®¡£
	
	£¨×¢Òâ£ºÕâÀïµÄÎ»ÖÃÖ¸µÄÊÇ´òÓ¡Ê±µÄÎ»ÖÃ£¬¶ø²»ÊÇÊµ¼ÊµÄÎ»ÖÃ¡££©

	The following functions are used to specify the location of the insertion in the specified string.
	(Note: This refers to the position of the printing position when, rather than the actual position.)
*/

int Console_InsStr(unsigned char *dest, const unsigned char *src, int disp_pos)
{
	int i, ins_len, str_len, actual_pos;

	ins_len = strlen((const char *)src);
	str_len = strlen((const char *)dest);

	actual_pos = Console_GetActualPos(dest, disp_pos);

	if (ins_len + str_len >= EDIT_LINE_MAX) return CONSOLE_MEM_ERR;
	if (actual_pos > str_len) return CONSOLE_ARG_ERR;

	for (i = str_len; i >= actual_pos; i--)
	{
		dest[i + ins_len] = dest[i];
	}

	for (i = 0; i < ins_len; i++)
	{
		dest[actual_pos + i] = src[i];
	}

	return CONSOLE_SUCCEEDED;
}

/*
	ÒÔÏÂº¯ÊýÓÃÓÚÈ·¶¨¶ÔÓ¦ÓÚ×Ö·û´®´òÓ¡Î»ÖÃµÄÕæÊµÎ»ÖÃ¡£
	
	ÀýÈç£¬ÔÚÒÔÏÂÕâÒ»°üº¬¿í×Ö·ûµÄ×Ö·û´®strÖÐ£¬´òÓ¡Ê±µÄÎ»ÖÃÈçÏÂ£º
	
	Î»ÖÃ | 00 | 01 | 02 | 03 | 04 | 05 | 06 |
	×Ö·û | Ò» | ¶þ | Èý | ËÄ | Îå | Áù | \0 |

	¶øÔÚÊµ¼Ê´æ´¢Ê±µÄÎ»ÖÃÈçÏÂ£º

	Î»ÖÃ |  00  |  01  |  02  |  03  |  04  |  05  |  06  |  07  |  08  |  09  |  10  |  11  |
	Öµ   | 0xD2 | 0xBB | 0xB6 | 0xFE | 0xC8 | 0xFD | 0xCB | 0xC4 | 0xCE | 0xE5 | 0xC1 | 0xF9 |

	¿ÉÒÔ·¢ÏÖ£¬µÚ4¸ö×Ö·û¡®Îå¡¯Êµ¼ÊÉÏ´æ´¢ÓÚµÚ8µÄÎ»ÖÃ¡£
	Òò´Ë£¬µ±µ÷ÓÃConsole_GetActualPos(str, 4)Ê±£¬½«·µ»Ø8¡£


	The following function is used to determine the true position of the string corresponding to the printing position.
	For example, in the following this string str contains wide characters, the location of the print is as follows:

	Location  | 00  |  01 |   02  |  03  | 04   | 05  | 06  |
	Character | one | two | three | four | five | six | \ 0 |

	The actual storage location is as follows:

	Location | 	00  | 01   |  02  |  03  |  04  |  05  |  06  |  07  |  08  |  09  |  10  |  11  |
	Value 	 | 0xD2 | 0xBB | 0xB6 | 0xFE | 0xC8 | 0xFD | 0xCB | 0xC4 | 0xCE | 0xE5 | 0xC1 | 0xF9 |

	You can find the first four characters 'five' is actually stored in the eighth position.
	So, when you call Console_GetActualPos (str, 4), it will return 8.
*/

int Console_GetActualPos(const unsigned char *str, int disp_pos)
{
	int actual_pos, count;

	for (actual_pos = count = 0; count < disp_pos; count++)
	{
		if (str[actual_pos] == '\0') return CONSOLE_ARG_ERR;

		if (is_wchar(str[actual_pos]))
		{
			actual_pos += 2;
		}
		else
		{
			actual_pos++;
		}
	}

	return actual_pos;
}

/*
	ÒÔÏÂº¯ÊýÓÃÓÚ»ñÈ¡×Ö·û´®µÄ´òÓ¡³¤¶È£¬¼´£¬1¸ö¿í×Ö·û£¨Õ¼ÓÃ2×Ö½Ú£©¼Ç×÷1×Ö·û¡£
	The following functions are used to obtain a string of print length, ie, a wide character (2 bytes) recorded as a character.
*/

int Console_GetDispLen(const unsigned char *str)
{
	int i, len;

	for (i = len = 0; str[i]!='\0'; len++)
	{
		if (is_wchar(str[i]))
		{
			i += 2;
		}
		else
		{
			i++;
		}
	}

	return len;
}

/*
	ÒÔÏÂº¯ÊýÓÃÓÚÒÆ¶¯¹â±ê¡£
	The following functions are used to move the cursor.
*/

int Console_MoveCursor(int direction)
{
	switch (direction)
	{
	case CURSOR_UP:
		//Èç¹ûÐèÒª²Ù×÷¡£
		//If you need to operate.
		if ((Cursor.y > 0) || (Start_Line > 0))
		{
			//Èç¹ûµ±Ç°ÐÐ²»ÊÇÖ»¶ÁµÄ,Ôò½«Edit_Line¿½±´¸øµ±Ç°ÐÐ¡£
			//If the current line is not read-only, then Edit_Line copy to the current line.
			if (!Line[Current_Line].readonly)
			{
				if ((Line[Current_Line].str = (unsigned char *)malloc(strlen((const char *)Edit_Line) + 1)) == NULL) return CONSOLE_MEM_ERR;
				strcpy((char *)Line[Current_Line].str, (const char *)Edit_Line);
				Line[Current_Line].disp_len = Console_GetDispLen(Line[Current_Line].str);
				Line[Current_Line].type = LINE_TYPE_INPUT;
			}

			//Èç¹û¹â±êÎ´ÒÆµ½×îÉÏ·½,ÔòÖ±½Ó½«¹â±êÏòÉÏÒÆ¡£
			//If the cursor does not move to the top of, directly move the cursor upward.
			if (Cursor.y > 0)
			{
				Cursor.y--;
			}
			//·ñÔò£¬Èç¹ûÆÁÄ»ÉÏÊ×ÐÐ²»ÊÇµÚÒ»ÐÐ£¬Ôò½«¿ªÊ¼ÏÔÊ¾µÄÐÐÊý¼õÒ»¡£
			//Otherwise, the number of rows, if the screen's first line is not the first line, then began to show minus one.
			else if (Start_Line > 0)
			{
				Start_Line--;
			}

			//Èç¹ûÒÆ¶¯ºó¹â±êË®Æ½Î»ÖÃ³¬¹ýÐÐÄ©£¬Ôò½«¹â±êÒÆÖÁÐÐÄ©¡£
			//End if the horizontal position after moving the cursor over the line, then move the cursor to the end of the line.
			if (Cursor.x > Line[Current_Line].disp_len)
			{
				Cursor.x = Line[Current_Line].disp_len;
			}
			else if (Line[Current_Line].disp_len - Line[Current_Line].start_col > COL_DISP_MAX)
			{
				if (Cursor.x == COL_DISP_MAX) Cursor.x = COL_DISP_MAX - 1;
			}

			//Èç¹ûÒÆ¶¯ºó¹â±êÔÚÐÐÊ×£¬ÇÒ¸ÃÐÐÇ°ÃæÓÐ×Ö·ûÎ´ÏÔÊ¾£¬Ôò½«¹â±êÒÆÖÁÎ»ÖÃ1¡£
			//If you move the cursor to the line after the first, and the front of the line there is a character does not appear, then move the cursor to position 1.
			if (Cursor.x == 0 && Line[Current_Line].start_col > 0) Cursor.x = 1;

			//Èç¹ûÏÖÔÚ¹â±êËùÔÚÐÐ²»ÊÇÖ»¶ÁµÄ£¬Ôò½«Æä×Ö·û´®¿½±´¸øEdit_LineÒÔ¹©±à¼­¡£
			//If the current cursor line is not read-only, then it is a string copy to Edit_Line for editing.
			if (!Line[Current_Line].readonly)
			{
				strcpy((char *)Edit_Line, (const char *)Line[Current_Line].str);
				free(Line[Current_Line].str);
				Line[Current_Line].str = Edit_Line;
			}
		}
		break;
	case CURSOR_DOWN:
		//Èç¹ûÐèÒª²Ù×÷¡£
		//If you need to operate.
		if ((Cursor.y < LINE_DISP_MAX - 1) && (Current_Line < Last_Line) || (Start_Line + LINE_DISP_MAX - 1 < Last_Line))
		{
			//Èç¹ûµ±Ç°ÐÐ²»ÊÇÖ»¶ÁµÄ,Ôò½«Edit_Line¿½±´¸øµ±Ç°ÐÐ¡£
			//If the current line is not read-only, then Edit_Line copy to the current line.
			if (!Line[Current_Line].readonly)
			{
				if ((Line[Current_Line].str = (unsigned char *)malloc(strlen((const char *)Edit_Line) + 1)) == NULL) return CONSOLE_MEM_ERR;
				strcpy((char *)Line[Current_Line].str, (const char *)Edit_Line);
				Line[Current_Line].disp_len = Console_GetDispLen(Line[Current_Line].str);
				Line[Current_Line].type = LINE_TYPE_INPUT;
			}

			//Èç¹û¹â±êÎ´ÒÆµ½×îÏÂ·½,ÔòÖ±½Ó½«¹â±êÏòÏÂÒÆ¡£
			//If the cursor does not move to the bottom, the cursor moves down directly.
			if (Cursor.y < LINE_DISP_MAX - 1 && Current_Line < Last_Line)
			{
				Cursor.y++;
			}
			//·ñÔò£¬Èç¹ûÆÁÄ»ÉÏÄ©ÐÐ²»ÊÇ×îºóÒ»ÐÐ£¬Ôò½«¿ªÊ¼ÏÔÊ¾µÄÐÐÊý¼ÓÒ»¡£
			//The number of rows Otherwise, if the last line is not the last line on the screen, it will begin to show a plus.
			else if (Start_Line + LINE_DISP_MAX - 1 < Last_Line)
			{
				Start_Line++;
			}

			//Èç¹ûÒÆ¶¯ºó¹â±êË®Æ½Î»ÖÃ³¬¹ýÐÐÄ©£¬Ôò½«¹â±êÒÆÖÁÐÐÄ©¡£
			//If you move the cursor after the end of the horizontal position over the line, then move the cursor to the end of the line.
			if (Cursor.x > Line[Current_Line].disp_len)
			{
				Cursor.x = Line[Current_Line].disp_len;
			}
			else if (Line[Current_Line].disp_len - Line[Current_Line].start_col >= COL_DISP_MAX)
			{
				if (Cursor.x == COL_DISP_MAX) Cursor.x = COL_DISP_MAX - 1;
			}

			//Èç¹ûÒÆ¶¯ºó¹â±êÔÚÐÐÊ×£¬ÇÒ¸ÃÐÐÇ°ÃæÓÐ×Ö·ûÎ´ÏÔÊ¾£¬Ôò½«¹â±êÒÆÖÁÎ»ÖÃ1¡£
			//If you move the cursor to the line after the first, and the front of the line there is a character does not appear, then move the cursor to position 1.
			if (Cursor.x == 0 && Line[Current_Line].start_col > 0) Cursor.x = 1;

			//Èç¹ûÏÖÔÚ¹â±êËùÔÚÐÐ²»ÊÇÖ»¶ÁµÄ£¬Ôò½«Æä×Ö·û´®¿½±´¸øEdit_LineÒÔ¹©±à¼­¡£
			//If the current cursor line is not read-only, then it is a string copy to Edit_Line for editing.
			if (!Line[Current_Line].readonly)
			{
				strcpy((char *)Edit_Line, (const char *)Line[Current_Line].str);
				free(Line[Current_Line].str);
				Line[Current_Line].str = Edit_Line;
			}
		}
		break;
	case CURSOR_LEFT:
		if (Line[Current_Line].readonly)
		{
			if (Line[Current_Line].start_col > 0) Line[Current_Line].start_col--;
		}
		else if (Line[Current_Line].start_col > 0)
		{
			if (Cursor.x > 1)
			{
				Cursor.x--;
			}
			else
			{
				Line[Current_Line].start_col--;
			}
		}
		else if (Cursor.x > 0) Cursor.x--;
		break;
	case CURSOR_RIGHT:
		if (Line[Current_Line].readonly)
		{
			if (Line[Current_Line].disp_len - Line[Current_Line].start_col > COL_DISP_MAX) Line[Current_Line].start_col++;
		}
		else if (Line[Current_Line].disp_len - Line[Current_Line].start_col > COL_DISP_MAX)
		{
			if (Cursor.x < COL_DISP_MAX - 1)
			{
				Cursor.x++;
			}
			else
			{
				Line[Current_Line].start_col++;
			}
		}
		else if (Cursor.x < Line[Current_Line].disp_len - Line[Current_Line].start_col) Cursor.x++;
		break;
	default:
		return CONSOLE_ARG_ERR;
		break;
	}
	return CONSOLE_SUCCEEDED;
}

/*
	ÒÔÏÂº¯ÊýÓÃÓÚÊäÈë¡£
	×Ö·û´®½«ÊäÈëµ½¹â±ê´¦£¬¹â±ê½«×Ô¶¯ÒÆ¶¯¡£
	
	The following function is used for input.
	String input to the cursor, the cursor will automatically move.
*/

int Console_Input(const unsigned char *str)
{
	int old_len,i,return_val;

	if (!Line[Current_Line].readonly)
	{
		old_len = Line[Current_Line].disp_len;
		return_val = Console_InsStr(Edit_Line, str, Current_Col);
		if (return_val != CONSOLE_SUCCEEDED) return return_val;
		if ((Line[Current_Line].disp_len = Console_GetDispLen(Edit_Line)) == CONSOLE_ARG_ERR) return CONSOLE_ARG_ERR;
		for (i = 0; i < Line[Current_Line].disp_len - old_len; i++)
		{
			Console_MoveCursor(CURSOR_RIGHT);
		}
		return CONSOLE_SUCCEEDED;
	}
	else
	{
		return CONSOLE_ARG_ERR;
	}
}

/*
	ÒÔÏÂº¯ÊýÓÃÓÚÊä³ö×Ö·û´®µ½µ±Ç°ÐÐ¡£
	The following functions are used to output the string to the current line.
*/

int Console_Output(const unsigned char *str)
{
	int return_val, old_len, i;

	if (!Line[Current_Line].readonly)
	{
		old_len = Line[Current_Line].disp_len;

		return_val = Console_InsStr(Edit_Line, str, Current_Col);
		if (return_val != CONSOLE_SUCCEEDED) return return_val;
		if ((Line[Current_Line].disp_len = Console_GetDispLen(Edit_Line)) == CONSOLE_ARG_ERR) return CONSOLE_ARG_ERR;
		Line[Current_Line].type = LINE_TYPE_OUTPUT;

		for (i = 0; i < Line[Current_Line].disp_len - old_len; i++)
		{
			Console_MoveCursor(CURSOR_RIGHT);
		}
		return CONSOLE_SUCCEEDED;
	}
	else
	{
		return CONSOLE_ARG_ERR;
	}
}

/*
	Clear the current output line
*/

int Console_Clear_EditLine()
{
	if(!Line[Current_Line].readonly) {
		Edit_Line[0] = '\0';
		Line[Current_Line].start_col = 0;
		Line[Current_Line].disp_len = 0;
		Cursor.x = 0;
	}
}

/*
	ÒÔÏÂº¯ÊýÓÃÓÚ´´½¨ÐÂÐÐ¡£
	²ÎÊýpre_line_typeÓÃÓÚÖ¸¶¨ÉÏÒ»ÐÐµÄÀàÐÍ£¬²ÎÊýpre_line_readonlyÓÃÓÚÖ¸¶¨ÉÏÒ»ÐÐÊÇ·ñÖ»¶Á¡£
	²ÎÊýnew_line_typeÓÃÓÚÖ¸¶¨ÏÂÒ»ÐÐµÄÀàÐÍ£¬²ÎÊýnew_line_readonlyÓÃÓÚÖ¸¶¨ÏÂÒ»ÐÐÊÇ·ñÖ»¶Á¡£

	The following functions are used to create a new line.
	Pre_line_type type parameter is used to specify the line, pre_line_readonly parameter is used to specify the line is read-only.
	New_line_type parameter is used to specify the type of the next line, new_line_readonly parameter is used to specify the next line is read-only.
*/

int Console_NewLine(int pre_line_type, int pre_line_readonly)
{
	int i;

	if (strlen((const char *)Edit_Line)||Line[Current_Line].type==LINE_TYPE_OUTPUT)
	{
		//Èç¹ûÒÑ¾­ÊÇËùÄÜ´æ´¢µÄ×îºóÒ»ÐÐ£¬ÔòÉ¾³ýµÚÒ»ÐÐ¡£
		//If this is the last line we can store, delete the first line.
		if (Last_Line == LINE_MAX - 1)
		{
			for (i = 0; i < Last_Line; i++)
			{
				Line[i].disp_len = Line[i + 1].disp_len;
				Line[i].readonly = Line[i + 1].readonly;
				Line[i].start_col = Line[i + 1].start_col;
				Line[i].str = Line[i + 1].str;
				Line[i].type = Line[i + 1].type;
			}
			Last_Line--;

			if (Start_Line > 0) Start_Line--;
		}

		if (Line[Last_Line].type == LINE_TYPE_OUTPUT && strlen((const char *)Edit_Line) == 0) Console_Output((const unsigned char *)"Done");
		
		if (TeX_isTeX((char*)Edit_Line)) Line[Last_Line].tex_flag = 1;
		if (Line[Last_Line].type == LINE_TYPE_OUTPUT && Line[Last_Line].tex_flag) TeX_sizeComplex ((char*)Edit_Line, &(Line[Last_Line].tex_width), &(Line[Last_Line].tex_height), NULL);
		else Line[Last_Line].tex_flag = 0;
		
		//½«Edit_LineµÄÄÚÈÝ¿½±´¸ø×îºóÒ»ÐÐ¡£
		//Edit_Line copy the contents to the last line.

#ifdef POPUP_PRETTY
		if(Line[Last_Line].tex_flag) {
			if ((Line[Last_Line].str = (unsigned char *)malloc(strlen(POPUP_PRETTY_STR) + 1)) == NULL) return CONSOLE_MEM_ERR;
			strcpy((char*)Line[Last_Line].str, (const char*)POPUP_PRETTY_STR);
			if ((Line[Last_Line].tex_str = (unsigned char *)malloc(strlen((const char *)Edit_Line) + 1)) == NULL) return CONSOLE_MEM_ERR;
			strcpy((char *)Line[Last_Line].tex_str, (const char *)Edit_Line);
		}
		else {
			if ((Line[Last_Line].str = (unsigned char *)malloc(strlen((const char *)Edit_Line) + 1)) == NULL) return CONSOLE_MEM_ERR;
			strcpy((char *)Line[Last_Line].str, (const char *)Edit_Line);
		}
#else
		if ((Line[Last_Line].str = (unsigned char *)malloc(strlen((const char *)Edit_Line) + 1)) == NULL) return CONSOLE_MEM_ERR;
		strcpy((char *)Line[Last_Line].str, (const char *)Edit_Line);
#endif

		if ((Line[Last_Line].disp_len = Console_GetDispLen(Line[Last_Line].str)) == CONSOLE_ARG_ERR) return CONSOLE_ARG_ERR;
		Line[Last_Line].type = pre_line_type;
		Line[Last_Line].readonly = pre_line_readonly;
		Line[Last_Line].start_col = 0;

		Edit_Line[0] = '\0';

		Last_Line++;

		Cursor.x = 0;

		if ((Last_Line - Start_Line) == LINE_DISP_MAX)
		{
			Start_Line++;
		}
		else
		{
			Cursor.y++;
		}

		Line[Last_Line].str = Edit_Line;
		Line[Last_Line].readonly = 0;
		Line[Last_Line].type = LINE_TYPE_INPUT;
		Line[Last_Line].start_col = 0;
		Line[Last_Line].disp_len = 0;

		return CONSOLE_NEW_LINE_SET;
	}
	else
	{
		return CONSOLE_NO_EVENT;
	}
}

/*
	ÒÔÏÂº¯ÊýÓÃÓÚÉ¾³ý¹â±êÇ°µÄÒ»¸ö×Ö·û¡£
	The following function is used to delete a character before the cursor.
*/

int Console_Backspace()
{
	int return_val;

	return_val = Console_DelStr(Edit_Line, Current_Col, 1);
	if (return_val != CONSOLE_SUCCEEDED) return return_val;
	Line[Current_Line].disp_len = Console_GetDispLen(Edit_Line);
	return Console_MoveCursor(CURSOR_LEFT);
}

/*
	ÒÔÏÂº¯ÊýÓÃÓÚ´¦Àí°´¼ü¡£
	The following functions are used to deal with the key.
*/

int Console_GetKey()
{
	unsigned int key, i, move_line, move_col;
	unsigned char tmp_str[2];
	unsigned char *tmp;

	GetKey(&key);
	 
	if (key >= '0' && key <= '9')
	{
		tmp_str[0] = key;
		tmp_str[1] = '\0';
		return Console_Input(tmp_str);
	}

	if (key >= KEY_CTRL_F1 && 
		key <= KEY_CTRL_F6)			return Console_FMenu(key);
	if (key == KEY_CHAR_IMGNRY)		return Console_Input((const unsigned char *)"i");
	if (key == KEY_CHAR_MAT)		return Console_Input((const unsigned char *)"matrix");
	if (key == KEY_CHAR_DP)			return Console_Input((const unsigned char *)".");
	if (key == KEY_CHAR_EQUAL)		return Console_Input((const unsigned char *)"=");
	if (key == KEY_CHAR_EXP)		return Console_Input((const unsigned char *)"*10^(");
	if (key == KEY_CHAR_DQUATE)		return Console_Input((const unsigned char *)"\"");
	if (key == KEY_CHAR_SPACE)		return Console_Input((const unsigned char *)" ");
	if (key == KEY_CHAR_PI)			return Console_Input((const unsigned char *)"pi");
	if (key == KEY_CHAR_PMINUS)		return Console_Input((const unsigned char *)"-");
	if (key == KEY_CHAR_MINUS)		return Console_Input((const unsigned char *)"-");
	if (key == KEY_CHAR_ANS)		return Console_Input((const unsigned char *)"last");
	if (key == KEY_CHAR_PLUS)		return Console_Input((const unsigned char *)"+");
	if (key == KEY_CHAR_LBRCKT)		return Console_Input((const unsigned char *)"[");
	if (key == KEY_CHAR_RBRCKT)		return Console_Input((const unsigned char *)"]");
	if (key == KEY_CHAR_MULT)		return Console_Input((const unsigned char *)"*");
	if (key == KEY_CHAR_LBRACE)		return Console_Input((const unsigned char *)"{");
	if (key == KEY_CHAR_DIV)		return Console_Input((const unsigned char *)"/");
	if (key == KEY_CHAR_RBRACE)		return Console_Input((const unsigned char *)"}");
	if (key == KEY_CHAR_FRAC)		return Console_Input((const unsigned char *)"/");
	if (key == KEY_CTRL_MIXEDFRAC)	return Console_Input((const unsigned char *)"simplify(");
	if (key == KEY_CTRL_FD)			return Console_Input((const unsigned char *)"float");
	if (key == KEY_CTRL_FRACCNVRT)	return Console_Input((const unsigned char *)"factor(");
	if (key == KEY_CHAR_LPAR)		return Console_Input((const unsigned char *)"(");
	if (key == KEY_CHAR_RPAR)		return Console_Input((const unsigned char *)")");
	if (key == KEY_CHAR_CUBEROOT)	return Console_Input((const unsigned char *)"^(1/3)");
	if (key == KEY_CHAR_RECIP)		return Console_Input((const unsigned char *)"^(-1)");
	if (key == KEY_CHAR_COMMA)		return Console_Input((const unsigned char *)",");
	if (key == KEY_CHAR_STORE)		return Console_Input((const unsigned char *)"!");
	if (key == KEY_CTRL_XTT)		return Console_Input((const unsigned char *)"x");
	if (key == KEY_CHAR_LOG)		return Console_Input((const unsigned char *)"log(");
	if (key == KEY_CHAR_EXPN10)		return Console_Input((const unsigned char *)"10^(");
	if (key == KEY_CHAR_LN)			return Console_Input((const unsigned char *)"ln(");
	if (key == KEY_CHAR_EXPN)		return Console_Input((const unsigned char *)"e^(");
	if (key == KEY_CHAR_SIN)		return Console_Input((const unsigned char *)"sin(");
	if (key == KEY_CHAR_ASIN)		return Console_Input((const unsigned char *)"arcsin(");
	if (key == KEY_CHAR_COS)		return Console_Input((const unsigned char *)"cos(");
	if (key == KEY_CHAR_ACOS)		return Console_Input((const unsigned char *)"arccos(");
	if (key == KEY_CHAR_TAN)		return Console_Input((const unsigned char *)"tan(");
	if (key == KEY_CHAR_ATAN)		return Console_Input((const unsigned char *)"arctan(");
	if (key == KEY_CHAR_SQUARE)		return Console_Input((const unsigned char *)"^2");
	if (key == KEY_CHAR_ROOT)		return Console_Input((const unsigned char *)"sqrt(");
	if (key == KEY_CHAR_VALR)		return Console_Input((const unsigned char *)"r");
	if (key == KEY_CHAR_POW)		return Console_Input((const unsigned char *)"^");
	if (key == KEY_CHAR_POWROOT)	return Console_Input((const unsigned char *)"^(1/");
	if (key == KEY_CHAR_THETA)		return Console_Input((const unsigned char *)"theta");

	if ((key >= 'A') && (key <= 'Z'))
	{
		if (Case == LOWER_CASE) key += 'a' - 'A';
		tmp_str[0] = key;
		tmp_str[1] = 0;
		return Console_Input(tmp_str);
	}

	if (key == KEY_CTRL_UP)		return Console_MoveCursor(CURSOR_UP);
	if (key == KEY_CTRL_DOWN)	return Console_MoveCursor(CURSOR_DOWN);
	if (key == KEY_CTRL_LEFT)	return Console_MoveCursor(CURSOR_LEFT);
	if (key == KEY_CTRL_RIGHT)	return Console_MoveCursor(CURSOR_RIGHT);

	if (key == KEY_CTRL_AC)
	{
		if (Line[Current_Line].readonly) return CONSOLE_NO_EVENT;
		Edit_Line[0] = '\0';
		Line[Current_Line].start_col = 0;
		Line[Current_Line].type = LINE_TYPE_INPUT;
		Line[Current_Line].disp_len = 0;
		Cursor.x = 0;
		return CONSOLE_SUCCEEDED;
	}

	if (key == KEY_CTRL_INS) {
		Start_Line = Current_Line;
		Cursor.y = 0;
	}

	if (key == KEY_CTRL_SETUP) {
		menu_setup();
	}

	if (key == KEY_CTRL_EXE)
	{
		if(Line[Current_Line].tex_flag) Console_Draw_TeX_Popup(Line[Current_Line].tex_str, Line[Current_Line].tex_width, Line[Current_Line].tex_height);
		else {
			if (Current_Line == Last_Line)
			{
				return Console_NewLine(LINE_TYPE_INPUT, 1);
			}
			else
			{
				return CONSOLE_ARG_ERR;
			}
		}
	}

	if (key == KEY_CTRL_DEL) return Console_Backspace();

	if (key == KEY_CTRL_CLIP)
	{
		if(Line[Current_Line].tex_flag) Console_Draw_TeX_Popup(Line[Current_Line].tex_str, Line[Current_Line].tex_width, Line[Current_Line].tex_height);
		else {
			tmp = Line[Current_Line].str;

			move_line = Last_Line - Current_Line;
			for (i = 0; i <= move_line; i++) Console_MoveCursor(CURSOR_DOWN);

			move_col = Line[Current_Line].disp_len - Current_Col;
			for (i = 0; i <= move_col; i++) Console_MoveCursor(CURSOR_RIGHT);

			Console_Input(tmp);
		}
	}

	return CONSOLE_NO_EVENT;
}

int Console_FMenu(int key)
{
	int i, handle, ret, matched = 0, number=0;
	unsigned int error_key;
	struct FMenu entry = {0};
	char* tmp_realloc = NULL;
	char temp[30] = {'\0'};
	char* original_cfg;
	char* cfg = memory_load("\\\\fls0\\FMENU.cfg");

	original_cfg = cfg;

	while(*cfg) {
		//Get each line
		for(i=0; i<20, *cfg && *cfg!='\r' && *cfg!='\n'; i++, cfg++) {
			temp[i] = *cfg;
		}

		//If starting by 'F' followed by the right number, start filling the structure.
		if(temp[0] == 'F' && temp[1]==(key-KEY_CTRL_F1)+'1') matched = 1;
		else if(temp[0] == 'F' && temp[1]!=(key-KEY_CTRL_F1)+'0') matched = 0;

		//Fill the structure
		else if(matched && temp[0] && entry.count < MAX_FMENU_ITEMS) {
			//Alloc a new string a copy current data into it
			tmp_realloc=(char*)entry.str;
			entry.str = realloc(tmp_realloc, sizeof(unsigned char*)*(entry.count+1));
			
			if(entry.str != NULL) {
				entry.str[entry.count] = (char*)malloc(strlen(temp)+1);

				if(entry.str[entry.count] == NULL) {
					PrintMini(10,40, (unsigned char*)"Error realloc bis -> Console_FMenu()", MINI_OVER);
					GetKey(&error_key);
					entry.str = (char*)realloc(entry.str, entry.count); //May never fail.
					entry.count--;
				}

				else strcpy(entry.str[entry.count], temp);

				entry.count++;
			}
			else {
				PrintMini(50,40, (unsigned char*)"Error realloc -> Console_FMenu()", MINI_OVER);
				GetKey(&error_key);
				entry.str = tmp_realloc;
			}
		}
		memset(temp, '\0', 30);
		cfg++;
	}

	free(original_cfg);

	if(entry.count > 0) {
		ret = Console_Draw_FMenu(key, &entry);
		for(i=0; i < entry.count; i++) {
			free(entry.str[i]);
		}
		free(entry.str);
		free(entry.name);
	}

	else return 0;
}

char *Console_Make_Entry(const unsigned char* str)
{
	char* entry = NULL;
	entry = (char*)calloc((strlen(str)+1), sizeof(unsigned char*));
	if(entry) memcpy(entry, str, strlen(str)+1);

	return entry;
}

//Draws and runs the asked for menu.
int Console_Draw_FMenu(int key, struct FMenu* menu)
{
	int i, nb_entries = 0, selector = 0, position_number, position_x, ret, longest = 0;
	unsigned int input_key;
	char quick[] = "*: ";
	int quick_len = 2;
	char **entries;
	DISPBOX box;

	position_number = key - KEY_CTRL_F1;

	entries  = menu->str;
	nb_entries = menu->count;

	for(i=0; i<nb_entries; i++)
		if(strlen(entries[i]) > longest) longest = strlen(entries[i]);

	position_x = 21*position_number;
	if(position_x + longest*4 + quick_len*4 > 115) position_x = 115 - longest*4 - quick_len*4;

	box.left = position_x;
	box.right = position_x + longest*4 + quick_len*4  + 6;
	box.bottom = 63-9;
	box.top = 63-9-nb_entries*7;

	Bdisp_AreaClr_VRAM(&box);

	Bdisp_DrawLineVRAM(box.left, box.bottom, box.left, box.top);
	Bdisp_DrawLineVRAM(box.right, box.bottom, box.right, box.top);

	//If the cursor is flashing on the opening box, disable it.
	if(((Cursor.x*(128/21)<box.right && Cursor.x*(128/21)>box.left)) 
		&& ((Cursor.y*(64/8)<box.bottom) && (Cursor.y*(64/8)>box.top))) Cursor_SetFlashOff();

	while(input_key != KEY_CTRL_EXE || input_key != KEY_CTRL_EXIT) {
		for(i=0; i<nb_entries; i++) {
			quick[0] = '0'+(i+1);
			PrintMini(3+position_x, box.bottom-7*(i+1), (unsigned char*)quick, MINI_OVER);
			PrintMini(3+position_x+quick_len*4, box.bottom-7*(i+1), (unsigned char*)entries[i], MINI_OVER);
		}
		PrintMini(3+position_x+quick_len*4,box.bottom-7*(selector+1), (unsigned char*)entries[selector], MINI_REV);
		GetKey(&input_key);

		if (input_key == KEY_CTRL_UP && selector < nb_entries-1) selector++;	
		if (input_key == KEY_CTRL_DOWN && selector > 0) selector--;

		if (input_key == KEY_CTRL_EXE) return Console_Input((unsigned char *)entries[selector]);

		if (input_key >= KEY_CHAR_1 && input_key < KEY_CHAR_1 + nb_entries) return Console_Input((unsigned char*)entries[input_key-KEY_CHAR_1]);

		if (input_key == KEY_CTRL_EXIT) return Console_Input((const unsigned char *)"");	

		if (input_key >= KEY_CTRL_F1 && input_key <= KEY_CTRL_F6) {
			Console_Input((const unsigned char *)"");
			Console_Disp();
			return Console_FMenu(input_key);
		}
	}
}

/*
	ÒÔÏÂº¯ÊýÓÃÓÚ³õÊ¼»¯¡£
*/

int Console_Init()
{
	int i;
	
	Start_Line = 0;
	Last_Line = 0;

	for (i = 0; i < LINE_MAX; i++)
	{
		if(Line[i].str) free(Line[i].str);
		Line[i].readonly = 0;
		Line[i].type = LINE_TYPE_INPUT;
		Line[i].start_col = 0;
		Line[i].disp_len = 0;
	}

	if ((Edit_Line = (unsigned char *)malloc(EDIT_LINE_MAX + 1)) == NULL) return CONSOLE_MEM_ERR;
	Line[0].str = Edit_Line;

	Cursor.x = 0;
	Cursor.y = 0;

	Case = LOWER_CASE;

	/*for(i = 0; i < 6; i++) {
		FMenu_entries[i].name = NULL;
		FMenu_entries[i].count = 0;
	}*/

	Console_FMenu_Init();

	return CONSOLE_SUCCEEDED;
}

// Loads the FMenus' data into memory, from a cfg file
void Console_FMenu_Init()
{
	int i, number=0, key, handle;
	unsigned char* tmp_realloc = NULL;
	unsigned char temp[20] = {'\0'};
	unsigned char* original_cfg;
	unsigned char* cfg = memory_load("\\\\fls0\\FMENU.cfg");


	// Does the file exists ?
	// Todo : check the error codes...
	if(!cfg) {
		unsigned char conf_standard[] = {"F1 calc\nderive(\nintegral(\ntaylor(\nsum(\nproduct(\nsimplify(\nfactor(\nF2 trig\ncosh(\narccosh(\nsinh(\narcsinh(\ntanh(\narctanh(\nF3 cplx\nmag(\narg(\nreal(\nimag(\nconj(\npolar(\nrect(\nF4 alge\nabs(\ndet(\nadj(\ncross(\ncurl(\ncontract(\nhilbert(\nF5 poly\nnroots(\ndeg(\ncoeff(\nquotient(\nhermite(\nlaguerre(\nlegendre(\nF6 arit\nmod(\ngcd(\nlcd(\nisprime(\nprime(\nfactor(\n"};
		memory_createfile("\\\\fls0\\FMENU.cfg", strlen((char*)conf_standard)+1);
		handle = memory_openfile("\\\\fls0\\FMENU.cfg", _OPENMODE_READWRITE);
		memory_writefile(handle, conf_standard, strlen((char*)conf_standard)+1);
		memory_closefile(handle);

		cfg = memory_load("\\\\fls0\\FMENU.cfg");
	}

	original_cfg = cfg;

	while(*cfg) {
		//Get each line
		for(i=0; i<20, *cfg && *cfg!='\r' && *cfg!='\n'; i++, cfg++) {
			temp[i] = *cfg;
		}

		//If starting by 'F', adjust the number and eventually set the name of the menu
		if(temp[0] == 'F' && temp[1]>='1' && temp[1]<='6') {
			number = temp[1]-'0' - 1;
			if(temp[3]) {
					strncpy((char*)FMenu_entries_name+(number*FMENU_TITLE_LENGHT), (char*)temp+3, FMENU_TITLE_LENGHT);
					//FMenu_entries[number].name[4] = '\0';
			}
		}

		memset(temp, '\0', 20);
		cfg++;
	}
	FMenu_entries_name[6*FMENU_TITLE_LENGHT] = '\0';
	free(original_cfg);
}

/*
	ÒÔÏÂº¯ÊýÓÃÓÚÏÔÊ¾ËùÓÐÐÐ¡£
	×¢Òâ£ºµ÷ÓÃ¸Ãº¯Êýºó£¬½«Ê×ÏÈÇå¿ÕÏÔ´æ¡£
	The following functions are used to display all lines.
	Note: After calling this function, the first clear the memory.
*/

int Console_Disp()
{
	unsigned int* pBitmap;
	char temp_fkey[FMENU_TITLE_LENGHT] = {'\0'};
	int i, alpha_shift_status;
	DISPBOX ficon;
	int print_y = 0; //pixel y cursor
	int print_y_locate;

	Bdisp_AllClr_VRAM();

	//GetFKeyIconPointer( 0x01BE, &ficon );
	//DisplayFKeyIcon( i, ficon);

	//Reading each "line" that will be printed
		for (i = 0; (i < LINE_DISP_MAX) && (i + Start_Line <= Last_Line); i++)
	{
		if (i == Cursor.y)
		{
			if (Line[i + Start_Line].type == LINE_TYPE_INPUT || Line[i + Start_Line].type == LINE_TYPE_OUTPUT && Line[i + Start_Line].disp_len >= COL_DISP_MAX)
			{
				locate(1, i + 1);

				if (Line[i + Start_Line].readonly)
				{
					Cursor_SetFlashMode(0);
					PrintRev(Line[i + Start_Line].str + Line[i + Start_Line].start_col);
				}
				else
				{
					if(Cursor.x > COL_DISP_MAX-1) {
						Print(Line[i + Start_Line].str + Line[i + Start_Line].start_col + 1);
					}
					else {
						Print(Line[i + Start_Line].str + Line[i + Start_Line].start_col);
					}
				}
			}
			else
			{
				locate(COL_DISP_MAX - Line[i + Start_Line].disp_len + 1, i + 1);

				if (Line[i + Start_Line].readonly)
				{
					Cursor_SetFlashMode(0);
					if(Line[i+Start_Line].tex_flag) {
						locate(COL_DISP_MAX - strlen(POPUP_PRETTY_STR) + 1,i+1);
						PrintRev((unsigned char*)POPUP_PRETTY_STR);
					}
					else {
						PrintRev(Line[i + Start_Line].str);
					}
				}
				else
				{
					Print(Line[i + Start_Line].str);
				}
			}

			if (Line[i + Start_Line].start_col > 0)
			{
				locate(1, i + 1);

				if (Line[i + Start_Line].readonly)
				{
					Cursor_SetFlashMode(0);
					PrintRev((unsigned char *)"\xE6\x9A");
				}
				else
				{
					Print((unsigned char *)"\xE6\x9A");
				}
			}

			if (Line[i + Start_Line].disp_len - Line[i + Start_Line].start_col > COL_DISP_MAX-1)
			{
				locate(COL_DISP_MAX, i + 1);
				if (Line[i + Start_Line].readonly)
				{
					if(Line[i + Start_Line].disp_len - Line[i + Start_Line].start_col != COL_DISP_MAX) {
						Cursor_SetFlashMode(0);
						PrintRev((unsigned char *)"\xE6\x9B");
					}
				}
				else if(Cursor.x < COL_DISP_MAX-1)
				{
					Print((unsigned char *)"\xE6\x9B");
				}
			}

			if (!Line[i + Start_Line].readonly)
			{
				switch(Setup_GetEntry(0x14)) {
					case 0: 
						alpha_shift_status = 0;
						break;
					case 1: //Shift enabled
						alpha_shift_status = 1;
						break;
					case 4:	//Alpha enabled
						alpha_shift_status = 4;
						break;
					case 0x84:	//both Shift and Alpha enabled, seems to be not working
						alpha_shift_status = 4;
						break;
					default: 
						alpha_shift_status = 0;
						break;
				}
				Cursor_SetPosition(Cursor.x, Cursor.y);
				Cursor_SetFlashMode(1);
				Cursor_SetFlashOn(alpha_shift_status);
				//Cursor_SetFlashStyle(alpha_shift_status); //Potential 2.00 OS incompatibilty (cf Simon's doc)
			}
		}
		else
		{
			if (Line[i + Start_Line].type == LINE_TYPE_INPUT || Line[i + Start_Line].type == LINE_TYPE_OUTPUT && Line[i + Start_Line].disp_len >= COL_DISP_MAX)
			{
				locate(1, i + 1);
				Print(Line[i + Start_Line].str + Line[i + Start_Line].start_col);
			}
			else
			{
				if(Line[i+Start_Line].tex_flag) {
					locate(COL_DISP_MAX - strlen(POPUP_PRETTY_STR) + 1, i + 1);
					Print((unsigned char*)POPUP_PRETTY_STR);
				}
				else {
					locate(COL_DISP_MAX - Line[i + Start_Line].disp_len + 1, i + 1);
					Print(Line[i + Start_Line].str);
				}
			}

			if (Line[i + Start_Line].start_col > 0)
			{
				locate(1, i + 1);
				Print((unsigned char *)"\xE6\xAF");
			}

			if (Line[i + Start_Line].disp_len - Line[i + Start_Line].start_col > COL_DISP_MAX)
			{
				locate(COL_DISP_MAX, i + 1);
				Print((unsigned char *)"\xE6\x9F");
			}
		}
	}

	//Draw the "fkeys icons"
	for(i=0; i<6; i++) {
		ficon.bottom = 64;
		ficon.top = 64-8;
		if (FMenu_entries_name[i*FMENU_TITLE_LENGHT]!= '\0') {
			ficon.left = 1+i*21;
			ficon.right = ficon.left + (127-2)/6 - 1;
			Bdisp_AreaClr_VRAM(&ficon);
			Bdisp_AreaReverseVRAM(ficon.left, ficon.top, ficon.right, ficon.bottom);
			memcpy(temp_fkey, FMenu_entries_name+i*FMENU_TITLE_LENGHT, FMENU_TITLE_LENGHT*sizeof(char));
			PrintMini(ficon.left + 2, ficon.top +2, (unsigned char*)temp_fkey, MINI_REV);
			memset(temp_fkey, '\0', FMENU_TITLE_LENGHT*sizeof(char));
		}
	}

	Bdisp_PutDisp_DD();
	return CONSOLE_SUCCEEDED;
}

/*
	Draw a popup at the center of the screen containing the str expression drawn in pretty print.
*/
#ifdef POPUP_PRETTY
void Console_Draw_TeX_Popup(unsigned char* str, int width, int height)
{
	DISPBOX popup;
	DISPBOX temp;
	unsigned char arrows[4*3] = {0xE6, 0x9A, '\0', 0xE6, 0x9B, '\0', 0xE6, 0x9C, '\0', 0xE6, 0x9D, '\0'};
	int margin = 2, border = 1;
	int scroll_lateral = 0, scroll_lateral_flag = 0, scroll_vertical = 0, scroll_vertical_flag = 0;
	int key;

	if(width > 115) {
		popup.left = 5;
		popup.right = 122;

		scroll_lateral_flag = 1;
	}
	else {
		popup.left = 64 - width/2 - margin - border;
		popup.right = 128 - popup.left;
	}

	if(height > 50) {
		popup.top = 5;
		popup.bottom = 57;

		scroll_vertical_flag = 1;
	}
	else {
		popup.top = 32 - height/2 - margin - border;
		popup.bottom = 64 - popup.top;
	}

	/*temp.left = 0; temp.top = 0; temp.right = 128; temp.bottom = 64;
	Bdisp_ReadArea_VRAM (&temp, vram_copy);*/
	
	while(key != KEY_CTRL_EXIT) {
		Bdisp_AreaClr_VRAM(&popup);
		Bdisp_AreaReverseVRAM(popup.left, popup.top, popup.right, popup.bottom);

		Bdisp_AreaReverseVRAM(popup.left + border, popup.top + border, popup.right - border, popup.bottom - border);

		TeX_drawComplex((char*)str, popup.left+border+margin + scroll_lateral, popup.top+border+margin + scroll_vertical); 

		if(scroll_lateral_flag ||scroll_vertical_flag) {
			temp.left = 0; temp.top = 0; temp.right = popup.left-1; temp.bottom = popup.bottom;
			Bdisp_AreaClr_VRAM(&temp);
			temp.left = 0; temp.top = popup.bottom+1; temp.right = 127; temp.bottom = 63;
			Bdisp_AreaClr_VRAM(&temp);
			temp.left = popup.left-1; temp.top = 0; temp.right = 127; temp.bottom = popup.top-1;
			Bdisp_AreaClr_VRAM(&temp);
			temp.left = popup.right+1; temp.top = popup.top-1; temp.right = 127; temp.bottom = 63;
			Bdisp_AreaClr_VRAM(&temp);

			if(scroll_lateral < 0) PrintMini(1, 30, arrows, 0);
			if(scroll_lateral > -(width - 115)) PrintMini(123, 30, arrows + 3, 0);
			if(scroll_vertical < 0) PrintMini(61, 0, arrows + 6, 0);
			if(scroll_vertical > -(height - 47)) PrintMini(61, 58, arrows + 9, 0);

			Bdisp_DrawLineVRAM(popup.left, popup.top, popup.left, popup.bottom);
			Bdisp_DrawLineVRAM(popup.left, popup.top, popup.right, popup.top);
			Bdisp_DrawLineVRAM(popup.left, popup.bottom, popup.right, popup.bottom);
			Bdisp_DrawLineVRAM(popup.right, popup.top, popup.right, popup.bottom);
		}

		GetKey(&key);

		if(scroll_lateral_flag) {
			if(key == KEY_CTRL_LEFT && scroll_lateral < 0) scroll_lateral += 5;
			if(key == KEY_CTRL_RIGHT && scroll_lateral > -(width - 115)) scroll_lateral -= 5;

			if(scroll_lateral > 0) scroll_lateral = 0;
		} 
		if(scroll_vertical_flag) {
			if(key == KEY_CTRL_UP && scroll_vertical < 0) scroll_vertical += 3;
			if(key == KEY_CTRL_DOWN && scroll_vertical > -(height - 47)) scroll_vertical -= 3;

			if(scroll_vertical > 0) scroll_vertical = 0;
		}
	}
}
#endif

/*
	ÒÔÏÂº¯ÊýÓÃÓÚÊäÈëÐÐ£¬³É¹¦ºó½«·µ»Ø¸ÃÐÐµÄ×Ö·û´®¡£
*/

unsigned char *Console_GetLine()
{
	int return_val;
	
	do
	{
		return_val = Console_GetKey();
		Console_Disp();
		if (return_val == CONSOLE_MEM_ERR) return NULL;
	} while (return_val != CONSOLE_NEW_LINE_SET);

	return Line[Current_Line - 1].str;
}

/*
	Simple accessor to the Edit_Line buffer.
*/
unsigned char* Console_GetEditLine()
{
	return Edit_Line;
}